home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / Source / Halma 1.1.source Folder / Halma ƒ / Shell ƒ / graphics.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-25  |  16.0 KB  |  468 lines  |  [TEXT/KAHL]

  1. /**********************************************************************\
  2.  
  3. File:        graphics.c
  4.  
  5. Purpose:    This module handles opening/closing/updating all windows:
  6.             this includes manipulating offscreen GWorlds & bitmaps
  7.             for fun and profit.
  8.  
  9. This program is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 2 of the License, or
  12. (at your option) any later version.
  13.  
  14. This program is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. GNU General Public License for more details.
  18.  
  19. You should have received a copy of the GNU General Public License
  20. along with this program in a file named "GNU General Public License".
  21. If not, write to the Free Software Foundation, 675 Mass Ave,
  22. Cambridge, MA 02139, USA.
  23.  
  24. \**********************************************************************/
  25.  
  26. #include "graphics.h"
  27. #include "about.h"
  28. #include "about MSG.h"
  29. #include "help.h"
  30. #include "dialogs.h"
  31. #include "error.h"
  32. #include "menus.h"
  33. #include "environment.h"
  34. #include "prefs.h"
  35. #include "program globals.h"
  36.  
  37. WindowPtr        gTheWindow[NUM_WINDOWS];            /* windowptr of nth window */
  38. ExtendedWindowDataHandle
  39.                 gTheWindowData[NUM_WINDOWS];        /* handle to nth window data struct */
  40.  
  41. /* internal global variables for use by graphics.c only */
  42. static    Rect        gBoundsRect[NUM_WINDOWS];        /* rectangle of offscreen bitmap */
  43. static    Rect        gMainScreenBounds;                /* bounds of main monitor */
  44. static    GWorldPtr    gTheGWorld[NUM_WINDOWS];        /* offscreen graphics world */
  45. static    Ptr            gBWBitMap[NUM_WINDOWS];            /* offscreen bitmap for B/W machines */
  46. static    GrafPort    gBWGrafPort[NUM_WINDOWS];        /* offscreen grafport "  "     "     */
  47. static    GrafPtr        gBWGrafPtr[NUM_WINDOWS];        /* offscreen grafptr  "  "     "     */
  48. static    GWorldPtr    currentGWorld;
  49. static    GDHandle    currentGDHandle;
  50.  
  51. Boolean InitTheGraphics(void)
  52. {
  53.     short            i;
  54.     
  55.     GetMainScreenBounds();
  56.     
  57.     for (i=0; i<NUM_WINDOWS; i++)
  58.     {
  59.         /* nothing is inited; if there's an error later on, we'll know how much to */
  60.         /* clean up in ShutDownTheGraphics() */
  61.         gTheWindow[i]=(WindowPtr)0L;
  62.         gTheGWorld[i]=(GWorldPtr)0L;
  63.         gTheWindowData[i]=(ExtendedWindowDataHandle)0L;
  64.     }
  65.     
  66.     for (i=0; i<NUM_WINDOWS; i++)
  67.     {
  68.         gTheWindowData[i]=(ExtendedWindowDataHandle)NewHandle(sizeof(ExtendedWindowDataRec));
  69.         if (gTheWindowData[i]==0L)                            /* return if error */
  70.             return FALSE;
  71.         
  72.         (**(gTheWindowData[i])).offscreenNeedsUpdate=TRUE;    /* offscreen not inited */
  73.         (**(gTheWindowData[i])).windowIndex=i;                /* so we can retrieve it O(1) */
  74.         (**(gTheWindowData[i])).windowDepth=
  75.             (**(gTheWindowData[i])).maxDepth=1;                /* init at B/W */
  76.         (**(gTheWindowData[i])).isColor=FALSE;                /* init to grayscale */
  77.         HLockHi((Handle)gTheWindowData[i]);
  78.     }
  79.     
  80.     /* set window dispatch routines */
  81.     (**(gTheWindowData[kAbout])).dispatchProc=(dispatchProcPtr)AboutBoxDispatch;        /* see about.c */
  82.     (**(gTheWindowData[kHelp])).dispatchProc=(dispatchProcPtr)HelpWindowDispatch;    /* see help.c */
  83.     (**(gTheWindowData[kAboutMSG])).dispatchProc=(dispatchProcPtr)AboutMSGBoxDispatch;/* see about MSG.c */
  84.     
  85.     /* call window dispatch routines with "startup" message */
  86.     ((**(gTheWindowData[kAbout])).dispatchProc)((WindowDataHandle)gTheWindowData[kAbout], kStartup, 0L);
  87.     ((**(gTheWindowData[kHelp])).dispatchProc)((WindowDataHandle)gTheWindowData[kHelp], kStartup, 0L);
  88.     ((**(gTheWindowData[kAboutMSG])).dispatchProc)((WindowDataHandle)gTheWindowData[kAboutMSG], kStartup, 0L);
  89.     
  90.     return TRUE;
  91. }
  92.  
  93. void OpenTheWindow(short index)
  94. {
  95.     if (!gTheWindow[index])        /* if window exists, we'll just update it (see below) */
  96.     {
  97.         if (((**(gTheWindowData[index])).dispatchProc)    /* call window's dispatch to */
  98.                 ((WindowDataHandle)gTheWindowData[index], kInitialize, 0L)==kFailure)    /* initialize it */
  99.         {        /* default is to center window on main screen */
  100.             (**(gTheWindowData[index])).initialTopLeft.h =
  101.                 gMainScreenBounds.left + (((gMainScreenBounds.right -
  102.                 gMainScreenBounds.left) - (**(gTheWindowData[index])).windowWidth) / 2);
  103.             (**(gTheWindowData[index])).initialTopLeft.v =
  104.                 gMainScreenBounds.top + (((gMainScreenBounds.bottom -
  105.                 gMainScreenBounds.top) - (**(gTheWindowData[index])).windowHeight) / 2);
  106.         }
  107.         
  108.         (**(gTheWindowData[index])).windowBounds.left=
  109.             (**(gTheWindowData[index])).initialTopLeft.h;
  110.         
  111.         (**(gTheWindowData[index])).windowBounds.top=
  112.             (**(gTheWindowData[index])).initialTopLeft.v;
  113.             
  114.         if (((**(gTheWindowData[index])).windowType==noGrowDocProc) ||
  115.             ((**(gTheWindowData[index])).windowType==documentProc) ||
  116.             ((**(gTheWindowData[index])).windowType==movableDBoxProc) ||
  117.             ((**(gTheWindowData[index])).windowType==zoomDocProc) ||
  118.             ((**(gTheWindowData[index])).windowType==zoomNoGrow) ||
  119.             ((**(gTheWindowData[index])).windowType==rDocProc))
  120.                 (**(gTheWindowData[index])).windowBounds.top += 9;    /* compensate for title */
  121.         
  122.         /* don't put window over menu bar */
  123.         if ((**(gTheWindowData[index])).windowBounds.top < GetMBarHeight()+1)
  124.             (**(gTheWindowData[index])).windowBounds.top = GetMBarHeight()+1;
  125.         
  126.         (**(gTheWindowData[index])).windowBounds.bottom =
  127.             (**(gTheWindowData[index])).windowBounds.top +
  128.             (**(gTheWindowData[index])).windowHeight;
  129.         
  130.         (**(gTheWindowData[index])).windowBounds.right =
  131.             (**(gTheWindowData[index])).windowBounds.left +
  132.             (**(gTheWindowData[index])).windowWidth;
  133.         
  134.         KillOffscreen(index);        /* kill offscreen bitmaps that are left over */
  135.         
  136.         if (gHasColorQD)
  137.         {
  138.             /* create the color window with our specs, see IM Essentials 4-79ff */
  139.             gTheWindow[index] = NewCWindow(0L, &((**(gTheWindowData[index])).windowBounds),
  140.                 (**(gTheWindowData[index])).windowTitle, FALSE,
  141.                 (**(gTheWindowData[index])).windowType, (WindowPtr)-1L,
  142.                 (**(gTheWindowData[index])).hasCloseBox,
  143.                 (unsigned long)gTheWindowData[index]);
  144.         }
  145.         else
  146.         {
  147.             /* create the B/W window with our specs, see IM Essentials 4-82ff */
  148.             gTheWindow[index] = NewWindow(0L, &((**(gTheWindowData[index])).windowBounds),
  149.                 (**(gTheWindowData[index])).windowTitle, FALSE,
  150.                 (**(gTheWindowData[index])).windowType, (WindowPtr)-1L,
  151.                 (**(gTheWindowData[index])).hasCloseBox,
  152.                 (unsigned long)gTheWindowData[index]);
  153.         }
  154.     }
  155.     
  156.     if (gTheWindow[index])
  157.     {
  158.         ShowWindow(gTheWindow[index]);            /* immediately show this new window */
  159.         SelectWindow(gTheWindow[index]);        /* immediately select this new window */
  160.         /* call window's dispatch routine to alert it that it's open now */
  161.         ((**(gTheWindowData[index])).dispatchProc)((WindowDataHandle)gTheWindowData[index], kOpen, 0L);
  162.         SetPort(gTheWindow[index]);                /* important! */
  163.         UpdateTheWindow((ExtendedWindowDataHandle)gTheWindowData[index]);    /* immediately update this new window */
  164.     }
  165.     else HandleError(kNoMemory, FALSE);            /* if unsuccessful, display error */
  166. }
  167.  
  168. void GetMainScreenBounds(void)
  169. {
  170.     gMainScreenBounds = screenBits.bounds;        /* low-mem global */
  171.     gMainScreenBounds.top += GetMBarHeight();    /* don't include menu bar */
  172. }
  173.  
  174. short GetBiggestDeviceDepth(WindowDataHandle theData)
  175. {
  176.     short            index;
  177.     Rect            tempRect;
  178.     long            biggestSize;
  179.     long            tempSize;
  180.     GDHandle        thisHandle, gBiggestDevice;
  181.     
  182.     if (!gHasColorQD)
  183.         return 1;
  184.     
  185.     index=(**theData).windowIndex;
  186.     
  187.     if (!gTheWindow[index])
  188.         return (**(**GetMainDevice()).gdPMap).pixelSize;
  189.     
  190.     thisHandle = GetDeviceList();
  191.     gBiggestDevice = 0L;
  192.     biggestSize = 0L;
  193.     
  194.     while (thisHandle)
  195.     {
  196.         if (TestDeviceAttribute(thisHandle, screenDevice) &&
  197.             TestDeviceAttribute(thisHandle, screenActive))
  198.         {
  199.             if (SectRect(&(gTheWindow[index]->portRect), &((**thisHandle).gdRect),
  200.                     &tempRect))
  201.             {
  202.                 if (biggestSize < (tempSize = ((long)(tempRect.bottom - tempRect.top))*
  203.                     ((long)(tempRect.right - tempRect.left))))
  204.                 {
  205.                     biggestSize = tempSize;
  206.                     gBiggestDevice = thisHandle;
  207.                 }
  208.             }
  209.         }
  210.         thisHandle = GetNextDevice(thisHandle);
  211.     }
  212.     
  213.     return (gBiggestDevice) ? (**(**gBiggestDevice).gdPMap).pixelSize : 1;
  214. }
  215.  
  216. short GetWindowDepth(WindowDataHandle theData)
  217. {
  218.     int                index;
  219.     
  220.     index=(**theData).windowIndex;
  221.     /* if Color Quickdraw is not available, the depth must be 1. */
  222.     /* if Color Quickdraw is available and the window exists, return the window's
  223.        GWorld's graphics device's pixel map's pixel depth */
  224.     /* if Color Quickdraw is available and the window does not exist, return the
  225.        pixel depth of the main screen */
  226.     return (gHasColorQD) ? ((gTheWindow[index]) ?
  227.             (**(**(GetGWorldDevice(gTheGWorld[index]))).gdPMap).pixelSize :
  228.             (**(**GetMainDevice()).gdPMap).pixelSize) : 1;
  229. }
  230.  
  231. Boolean WindowIsColor(WindowDataHandle theData)
  232. {
  233.     short            index;
  234.     
  235.     index=(**theData).windowIndex;
  236.     return (gHasColorQD) ? ((GetWindowDepth(theData)>8) ? TRUE :
  237.         TestDeviceAttribute(GetGWorldDevice(gTheGWorld[index]), gdDevType)) : FALSE;
  238. }
  239.  
  240. void UpdateTheWindow(ExtendedWindowDataHandle theData)
  241. {
  242.     short            index;
  243.     long            offRowBytes, sizeOfOff;
  244.     unsigned long    updateResult;
  245.     Boolean            isColor;
  246.     
  247.     index=(**theData).windowIndex;
  248.     gBoundsRect[index]=gTheWindow[index]->portRect;
  249.     OffsetRect(&gBoundsRect[index], -gBoundsRect[index].left, -gBoundsRect[index].top);
  250.  
  251.     if (gHasColorQD)    /* w/o Color Quickdraw, GWorlds may not be supported */
  252.     {
  253.         if (gTheGWorld[index]==0L)        /* create new graphics world if none exists */
  254.         {
  255.             /* try to create new graphics world; display error if unsuccessful */
  256.             if (NewGWorld(&gTheGWorld[index],
  257.                 (GetBiggestDeviceDepth(theData)>=(**theData).maxDepth) ?
  258.                 (**theData).maxDepth : 0, &gBoundsRect[index], 0L, 0L, 0)!=0)
  259.             {
  260.                 HandleError(kNoMemory, FALSE);
  261.                 return;
  262.             }
  263.             (**theData).windowDepth=GetWindowDepth((WindowDataHandle)theData);
  264.             NoPurgePixels(GetGWorldPixMap(gTheGWorld[index]));    /* never purge our pixmap! */
  265.             updateResult=1;
  266.         }
  267.         else updateResult=0;
  268.         
  269.         GetGWorld(¤tGWorld, ¤tGDHandle);    /* get current settings */
  270.         LockPixels(GetGWorldPixMap(gTheGWorld[index]));    /* important!  copybits may move mem */
  271.         /* update offscreen graphics world, compensating for change in pixel depth */
  272.         updateResult|=(unsigned long)UpdateGWorld(&gTheGWorld[index],
  273.             (GetBiggestDeviceDepth(theData)>=(**theData).maxDepth) ? (**theData).maxDepth :
  274.             0, &gBoundsRect[index], 0L, 0L, 0);
  275.         SetGWorld(gTheGWorld[index], 0L);                /* set to our offscreen gworld */
  276.         
  277.         isColor=WindowIsColor(theData);
  278.         if (isColor!=(**theData).isColor)
  279.         {
  280.             (**theData).isColor=isColor;
  281.             updateResult=1;
  282.         }
  283.         
  284.         if ((updateResult!=0L) || ((**theData).windowDepth!=GetWindowDepth(theData)))
  285.         {
  286.             FillRect(&gBoundsRect[index], black);
  287.             (**theData).windowDepth=GetWindowDepth((WindowDataHandle)theData);    /* save new depth */
  288.             (**theData).offscreenNeedsUpdate=TRUE;                /* we'll need to redraw */
  289.             ((**theData).dispatchProc)((WindowDataHandle)theData, kChangeDepth, 0L);
  290.         }
  291.     }
  292.     else    /* deal with (guaranteed) B/W bitmaps manually */
  293.     {
  294.         if (gBWGrafPtr[index]==0L)    /* create new offscreen bitmap if none exists */
  295.         {
  296.             gBWGrafPtr[index]=&gBWGrafPort[index];
  297.             OpenPort(gBWGrafPtr[index]);    /* make a new port */
  298.             
  299.             /* calculate the size of the offscreen bitmap from the boundsrect */
  300.             offRowBytes=(((gBoundsRect[index].right-gBoundsRect[index].left)+15)>>4)<<1;
  301.             sizeOfOff=(long)(gBoundsRect[index].bottom-gBoundsRect[index].top)*offRowBytes;
  302.             
  303.             gBWBitMap[index]=NewPtr(sizeOfOff);        /* allocate space for bitmap */
  304.             if (gBWBitMap[index]==0L)                /* abort if unsuccessful */
  305.             {
  306.                 ClosePort(gBWGrafPtr[index]);        /* cleaning up... */
  307.                 gBWGrafPtr[index]=0L;
  308.                 HandleError(kNoMemory, FALSE);        /* displaying error... */
  309.                 return;                                /* and aborting... */
  310.             }
  311.             
  312.             gBWGrafPort[index].portBits.baseAddr=gBWBitMap[index];    /* --> our bitmap */
  313.             gBWGrafPort[index].portBits.rowBytes=offRowBytes;        /* bitmap size */
  314.             gBWGrafPort[index].portBits.bounds=                        /* bitmap bounds */
  315.                 gBWGrafPort[index].portRect=gBoundsRect[index];
  316.             
  317.             SetPort(gBWGrafPtr[index]);
  318.             FillRect(&gBoundsRect[index], black);
  319.             (**theData).offscreenNeedsUpdate=TRUE;
  320.         }
  321.         else SetPort(gBWGrafPtr[index]);            /* set port for subsequent drawing */
  322.     }    
  323.     
  324.     if ((**theData).offscreenNeedsUpdate)            /* if we need to redraw */
  325.     {
  326.         (**theData).offscreenNeedsUpdate=FALSE;        /* not anymore */
  327.         /* call window's dispatch and tell it to redraw itself */
  328.         ((**theData).dispatchProc)((WindowDataHandle)theData, kUpdate, GetWindowDepth((WindowDataHandle)theData));
  329.     }
  330.     
  331.     if (gHasColorQD)
  332.         SetGWorld(currentGWorld, currentGDHandle);    /* restore old settings */
  333.     
  334.     SetPort(gTheWindow[(**theData).windowIndex]);
  335.     
  336.     /* copy offscreen bitmap from graphics world or bitmap to onscreen window */
  337.     CopyBits(gHasColorQD ? &(((GrafPtr)gTheGWorld[index])->portBits) :
  338.                 &(gBWGrafPtr[index]->portBits), &(gTheWindow[index]->portBits),
  339.                 &gBoundsRect[index], &gBoundsRect[index], 0, 0L);
  340.     
  341.     if (gHasColorQD)
  342.         UnlockPixels(GetGWorldPixMap(gTheGWorld[index]));    /* remember we locked these? */
  343.     
  344.     ValidRect(&(gTheWindow[index]->portRect));        /* so we don't reupdate */
  345. }
  346.  
  347. Boolean CloseTheWindow(ExtendedWindowDataHandle theData)
  348. {
  349.     short            index;
  350.     
  351.     index=(**theData).windowIndex;
  352.     
  353.     /* if the window's dispatch cancels the close, abort */
  354.     if (((**theData).dispatchProc)((WindowDataHandle)theData, kClose, 0L)==kCancel)
  355.         return FALSE;
  356.     
  357.     DisposeWindow(gTheWindow[index]);    /* get rid of the actual window in memory */
  358.     gTheWindow[index]=0L;                /* so _we_ know the window doesn't exist */
  359.     KillOffscreen(index);                /* kill offscreen bitmaps left over */
  360.     
  361.     /* tell window's dispatch that it's disposed of now */
  362.     ((**theData).dispatchProc)((WindowDataHandle)theData, kDispose, 0L);
  363.     
  364.     return TRUE;    /* successful close */
  365. }
  366.  
  367. PicHandle DrawThePicture(PicHandle thePict, short whichPict, short x, short y)
  368. /* a standard routine for loading a picture (if necessary) and then drawing it */
  369. {
  370.     Rect            temp;
  371.     
  372.     if (thePict==0L)        /* get it if it doesn't exist */
  373.         thePict=(PicHandle)GetPicture(whichPict);
  374.     
  375.     HLock((Handle)thePict);        /* lock it down for dereferencing to get picture bounds */
  376.     temp.top=y;
  377.     temp.left=x;
  378.     temp.bottom=temp.top+(**thePict).picFrame.bottom-(**thePict).picFrame.top;
  379.     temp.right=temp.left+(**thePict).picFrame.right-(**thePict).picFrame.left;
  380.     DrawPicture(thePict, &temp);    /* draw picture at (x,y) */
  381.     HUnlock((Handle)thePict);        /* unlock for better memory management */
  382.     return thePict;
  383. }
  384.  
  385. PicHandle ReleaseThePict(PicHandle thePict)
  386. {
  387.     if (thePict!=0L)    /* if exists, release it */
  388.         ReleaseResource((Handle)thePict);
  389.     return 0L;
  390. }
  391.  
  392. Boolean SetPortToOffscreen(WindowDataHandle theData)
  393. {
  394.     short            index;
  395.     
  396.     index=(**theData).windowIndex;
  397.     
  398.     if (gHasColorQD)
  399.     {
  400.         if (gTheGWorld[index]==0L)
  401.             return FALSE;
  402.         GetGWorld(¤tGWorld, ¤tGDHandle);    /* get current settings */
  403.         LockPixels(GetGWorldPixMap(gTheGWorld[index]));    /* important!  copybits may move mem */
  404.         SetGWorld(gTheGWorld[index], 0L);
  405.     }
  406.     else
  407.     {
  408.         if (gBWGrafPtr[index]==0L)
  409.             return FALSE;
  410.         SetPort(gBWGrafPtr[index]);
  411.     }
  412.     
  413.     return TRUE;
  414. }
  415.  
  416. void RestorePortToScreen(WindowDataHandle theData)
  417. {
  418.     if (gHasColorQD)
  419.     {
  420.         SetGWorld(currentGWorld, currentGDHandle);    /* restore old settings */
  421.         UnlockPixels(GetGWorldPixMap(gTheGWorld[(**theData).windowIndex]));
  422.     }
  423.     
  424.     SetPort(gTheWindow[(**theData).windowIndex]);
  425. }
  426.  
  427. GrafPtr GetOffscreenGrafPtr(WindowDataHandle theData)
  428. {
  429.     if (gHasColorQD)
  430.         return (GrafPtr)gTheGWorld[(**theData).windowIndex];
  431.     else
  432.         return gBWGrafPtr[(**theData).windowIndex];
  433. }
  434.  
  435. GrafPtr GetWindowGrafPtr(WindowDataHandle theData)
  436. {
  437.     return (GrafPtr)gTheWindow[(**theData).windowIndex];
  438. }
  439.  
  440. void KillOffscreen(int index)
  441. {
  442.     if (gTheGWorld[index]!=0L)
  443.         DisposeGWorld(gTheGWorld[index]);
  444.     if (gBWGrafPtr[index]!=0L)
  445.         DisposePtr((Ptr)gBWGrafPtr[index]);
  446.     gTheGWorld[index]=0L;
  447.     gBWGrafPtr[index]=0L;
  448. }
  449.  
  450. void ShutDownTheGraphics(void)
  451. {
  452.     short            i;
  453.     
  454.     /* send shutdown messages to the shell's windows */
  455.     ((**(gTheWindowData[kAbout])).dispatchProc)((WindowDataHandle)gTheWindowData[kAbout], kShutdown, 0L);
  456.     ((**(gTheWindowData[kHelp])).dispatchProc)((WindowDataHandle)gTheWindowData[kHelp], kShutdown, 0L);
  457.     ((**(gTheWindowData[kAboutMSG])).dispatchProc)((WindowDataHandle)gTheWindowData[kAboutMSG], kShutdown, 0L);
  458.     
  459.     for (i=0; i<NUM_WINDOWS; i++)
  460.     {
  461.         KillOffscreen(i);
  462.         if (gTheWindowData[i]!=0L)
  463.             DisposeHandle((Handle)gTheWindowData[i]);
  464.         if (gTheWindow[i]!=0L)
  465.             DisposeWindow(gTheWindow[i]);
  466.     }
  467. }
  468.